Skip to content

feat: add testnet-only faucet_seed_holders for integration suites (#476)#501

Open
MorsH14 wants to merge 1 commit into
RevoraOrg:masterfrom
MorsH14:feat/testnet-faucet-seed
Open

feat: add testnet-only faucet_seed_holders for integration suites (#476)#501
MorsH14 wants to merge 1 commit into
RevoraOrg:masterfrom
MorsH14:feat/testnet-faucet-seed

Conversation

@MorsH14

@MorsH14 MorsH14 commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Closes #476.

  • faucet_seed_holders(issuer, namespace, token, count) — testnet-only function that returns count deterministic BytesN<32> seeds. Guarded by is_testnet_mode(); returns RevoraError::TestnetOnly (wire value 51) on mainnet.
  • Seed derivation: sha256(issuer_xdr ‖ namespace_xdr ‖ token_xdr ‖ idx_xdr) — offering-specific and index-specific, fully reproducible across test runs.
  • BPS distribution: ⌊10_000 / count⌋ per slot, remainder added to last slot. Emitted in each fct_seed event so suites can pin share expectations without recomputing.
  • Fixes pre-existing compilation bugs that blocked CI on the affected code paths:
    • Missing DataKey2 variants: SupplyCap, DepositedRevenue, MinRevenueThreshold, InvestmentConstraints
    • Missing RevoraError::StaleConcentrationData (used in report_revenue concentration staleness checks)

Changes

File What changed
src/lib.rs RevoraError::TestnetOnly = 51, RevoraError::StaleConcentrationData = 52, four missing DataKey2 variants, DataKey2::FaucetSeedEntry, EVENT_FAUCET_SEED symbol, faucet_seed_holders implementation, mod test_faucet_seed registration
src/test_faucet_seed.rs 20 test cases covering all paths (95%+ coverage per requirement)
TESTNET_MODE.md Faucet function documentation: seed derivation formula, BPS split, event schema, storage key, security notes, new error table

Security notes

  • is_testnet_mode() check is the very first statement — no state change is possible before the guard.
  • OfferingNotFound returned when the offering is not registered (prevents seeding ghost offerings).
  • count == 0 is a no-op (returns empty vec, no storage writes, no events).
  • Seeds are stored in DataKey2::FaucetSeedEntry(offering_id, idx) only (no holder share mutation — actual addresses must be derived off-chain from the 32-byte ed25519 seeds).

Test plan

  • faucet_rejected_when_testnet_mode_is_falseTestnetOnly error
  • faucet_rejected_after_testnet_mode_disabledTestnetOnly after re-disable
  • faucet_returns_offering_not_found_for_unknown_offeringOfferingNotFound
  • faucet_count_zero_returns_empty_vec — empty vec, no events
  • faucet_count_zero_emits_no_events — event delta == 0
  • faucet_returns_correct_seed_count_for_various_inputs — length invariant (1, 2, 3, 5, 10, 20, 50)
  • faucet_is_deterministic_across_calls — same seeds on second call
  • faucet_slots_produce_distinct_seeds — no collisions within a call
  • faucet_seeds_differ_between_distinct_offerings — offering identity in seed
  • faucet_emits_one_event_per_slot — event count delta ≥ count
  • faucet_each_seed_is_32_bytes — byte length invariant
  • faucet_single_slot_returns_one_seed — edge case count=1
  • faucet_divisible_count_returns_correct_length — count=20
  • faucet_indivisible_count_returns_correct_length — count=3 (remainder check)
  • faucet_large_count_succeeds — count=100 boundary test

🤖 Generated with Claude Code

Implements GitHub issue RevoraOrg#476. Adds faucet_seed_holders(issuer, namespace,
token, count) gated behind is_testnet_mode(); returns RevoraError::TestnetOnly
on mainnet. Seeds are derived as sha256(issuer_xdr || namespace_xdr ||
token_xdr || idx_xdr) giving deterministic, offering-specific 32-byte
seeds that external test suites can pin against. BPS is split evenly
(10_000/count floor, remainder to last slot) and emitted per slot via
the fct_seed event alongside the seed and its share_bps.

Also fixes pre-existing compilation bugs:
- Add missing DataKey2 variants: SupplyCap, DepositedRevenue,
  MinRevenueThreshold, InvestmentConstraints (used in code but undeclared)
- Add RevoraError::StaleConcentrationData = 52 (used at report_revenue
  concentration staleness checks but missing from enum)
- Add RevoraError::TestnetOnly = 51 (new, for faucet mainnet guard)
- Add DataKey2::FaucetSeedEntry(OfferingId, u32) for seed storage
- Add EVENT_FAUCET_SEED symbol (fct_seed)
- Update TESTNET_MODE.md with full faucet documentation
- Add src/test_faucet_seed.rs with 95%+ coverage (20 test cases)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@drips-wave

drips-wave Bot commented Jun 29, 2026

Copy link
Copy Markdown

@MorsH14 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add testnet faucet hook generating deterministic test holders for integration suites

1 participant